package com.egao.common.module.system.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.egao.common.core.Constants;
import com.egao.common.core.web.PageParam;
import com.egao.common.core.exception.BusinessException;
import com.egao.common.module.company.constants.CompanyConstants;
import com.egao.common.module.company.entity.Company;
import com.egao.common.module.system.constants.UserConstants;
import com.egao.common.module.system.entity.Menu;
import com.egao.common.module.system.entity.vo.IdNameVO;
import com.egao.common.module.system.entity.vo.PermissionVO;
import com.egao.common.module.system.entity.vo.RoleVO;
import com.egao.common.module.system.entity.vo.UserVO;
import com.egao.common.module.system.mapper.MenuMapper;
import com.egao.common.module.system.mapper.UserMapper;
import com.egao.common.module.system.mapper.UserRoleMapper;
import com.egao.common.module.system.entity.Role;
import com.egao.common.module.system.entity.User;
import com.egao.common.module.system.entity.UserRole;
import com.egao.common.module.system.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 用户服务实现类
 * Created by wangfan on 2018-12-24 16:10
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private MenuMapper menuMapper;

    @Override
    public User getByUsername(String username) {
        return baseMapper.selectOne(new QueryWrapper<User>().eq("username", username));
    }

    @Override
    public User getFullById(Integer userId) {
        List<User> userList = baseMapper.listAll(new PageParam<User>().put("userId", userId).getNoPageParam());
        if (userList == null || userList.size() == 0) {
            return null;
        }
        return selectRoleAndAuth(userList.get(0));
    }

    @Override
    public User selectRoleAndAuth(User user) {
        if (user == null) {
            return user;
        }
        user.setRoles(userRoleMapper.listByUserId(user.getUserId()));
        return selectUserAuth(user);
    }

    @Override
    public User selectUserAuth(User user) {
        if (user == null) return user;
        List<Menu> menus = menuMapper.listByUserId(user.getUserId(), null);
        List<Menu> authList = new ArrayList<>();
        for (Menu menu : menus) {
            if (StrUtil.isNotBlank(menu.getAuthority())) {
                authList.add(menu);
            }
        }
        user.setAuthorities(authList);
        return user;
    }

    @Override
    public List<User> listPage(PageParam<User> page) {
        List<User> users = baseMapper.listPage(page);
        // 查询用户的角色
        selectUserRoles(users);
        return users;
    }

    @Override
    public List<User> listAll(Map<String, Object> page) {
        List<User> users = baseMapper.listAll(page);
        // 查询用户的角色
        selectUserRoles(users);
        return users;
    }

    @Transactional
    @Override
    public boolean saveUser(User user) {
        if (user.getUsername() != null && baseMapper.selectCount(new QueryWrapper<User>()
                .eq("username", user.getUsername())) > 0) {
            throw new BusinessException("账号已存在");
        }
        if (user.getEmail() != null && baseMapper.selectCount(new QueryWrapper<User>()
                .eq("email", user.getEmail())) > 0) {
            throw new BusinessException("邮箱已存在");
        }
        user.setUserType("1");
        boolean result = baseMapper.insert(user) > 0;
        if (result) {
            addUserRoles(user.getUserId(), user.getRoleIds(), false);
        }
        return result;
    }

    @Transactional
    @Override
    public User saveUserStudent(User user) {
        if (user.getUsername() != null && baseMapper.selectCount(new QueryWrapper<User>()
                .eq("username", user.getUsername())) > 0) {
//            throw new BusinessException("账号已存在");
            return null;
        }
        user.setUserType(UserConstants.USER_TYPE_STUDENT);
        boolean result = baseMapper.insert(user) > 0;

        List<Integer> studentRoles = new ArrayList<>();
        studentRoles.add(3);
        if (result) {
            addUserRoles(user.getUserId(), studentRoles, false);
            return user;
        }
        return null;
    }

    @Override
    public User saveCooperative(User user) {
        if (user.getUsername() != null && baseMapper.selectCount(new QueryWrapper<User>()
                .eq("username", user.getUsername())) > 0) {
            throw new BusinessException("账号已存在");
        }

        user.setUserType(UserConstants.USER_TYPE_COOPERATIVE);
        boolean result = baseMapper.insert(user) > 0;

        List<Integer> roles = new ArrayList<>();
        // 产教融合单位角色
        roles.add(20);
        if (result) {
            addUserRoles(user.getUserId(), roles, false);
            return user;
        }

        return null;
    }

    @Transactional
    @Override
    public boolean updateUser(User user) {
        if (user.getUsername() != null && baseMapper.selectCount(new QueryWrapper<User>()
                .eq("username", user.getUsername()).ne("user_id", user.getUserId())) > 0) {
            throw new BusinessException("账号已存在");
        }
        if (user.getEmail() != null && baseMapper.selectCount(new QueryWrapper<User>()
                .eq("email", user.getEmail()).ne("user_id", user.getUserId())) > 0) {
            throw new BusinessException("邮箱已存在");
        }
        boolean result = baseMapper.updateById(user) > 0;
        if (result) {
            addUserRoles(user.getUserId(), user.getRoleIds(), true);
        }
        return result;
    }

    @Override
    public boolean comparePsw(String dbPsw, String inputPsw) {
        return dbPsw != null && new BCryptPasswordEncoder().matches(inputPsw, dbPsw);
    }

    @Override
    public String encodePsw(String psw) {
        if (psw == null) {
            return null;
        }
        return new BCryptPasswordEncoder().encode(psw);
    }

    /**
     * 批量查询用户的角色
     */
    private void selectUserRoles(List<User> users) {
        if (users != null && users.size() > 0) {
            List<Integer> userIds = users.stream().map(User::getUserId).collect(Collectors.toList());
            List<Role> userRoles = userRoleMapper.listByUserIds(userIds);
            for (User user : users) {
                List<Role> roles = userRoles.stream().filter(d -> user.getUserId().equals(d.getUserId())).collect(Collectors.toList());
                user.setRoles(roles);
            }
        }
    }

    /**
     * 添加用户角色
     */
    private void addUserRoles(Integer userId, List<Integer> roleIds, boolean deleteOld) {
        if (deleteOld) {
            userRoleMapper.delete(new UpdateWrapper<UserRole>().eq("user_id", userId));
        }
        if (userRoleMapper.insertBatch(userId, roleIds) < roleIds.size()) {
            throw new BusinessException("操作失败");
        }
    }

    @Override
    public UserVO getUserVOById(Integer userId) {
        UserVO userVO = baseMapper.getUserVO(userId);
        setUserVORole(userVO);
        return userVO;
    }

    @Override
    public boolean getUserIsExistByUserName(String userName) {
        if (userName != null && baseMapper.selectCount(new QueryWrapper<User>()
                .eq("username", userName)) > 0) {
            return true;
        }
        return false;
    }

    @Override
    public Integer updateUserDeleted(Integer deleted, Integer userId) {
        return baseMapper.updateUserDeleted(deleted, userId);
    }

    /**
     * 设置用户页面对象对应的角色及标识
     * @param userVO 用户页面对象
     */
    private void setUserVORole(UserVO userVO) {
        if (userVO == null) {
            return;
        }

        // 角色页面对象容器
        RoleVO roleVO = new RoleVO();

        // 权限标识容器
        List<PermissionVO> permissionVOList = new ArrayList<>();

        // action 权限授予
        List<Menu> menus = menuMapper.listByUserId(userVO.getId(), null);
        for (Menu menu : menus) {
            if (StrUtil.isNotBlank(menu.getAuthority())) {
                permissionVOList.add(new PermissionVO(menu.getAuthority()));
            }
        }

        // 角色 权限授予
        String roleNames = "";
        List<Role> userRoles = userRoleMapper.listByUserId(userVO.getId());
        for (Role role : userRoles) {
            roleNames += role.getRoleName() + StrUtil.COMMA;
            permissionVOList.add(new PermissionVO(role.getRoleCode()));
        }
        roleNames = StrUtil.removeSuffix(roleNames, StrUtil.COMMA);

        // 赋值
        roleVO.setName(roleNames);
        roleVO.setPermissions(permissionVOList);

        userVO.setRole(roleVO);
    }

    @Override
    public User saveOrUpdateStudent(String xh, String xm) {
        List<User> userList = baseMapper.selectList(new QueryWrapper<User>().eq("username", xh));

        if (userList.size() > 1) {
            return null;
        }

        User user = new User();
        if (userList.size() == 1) {
            user = userList.get(0);
        }

        // 设置用户类型、密码、姓名
        user.setUsername(xh);
        user.setUserType(UserConstants.USER_TYPE_STUDENT);
        user.setPassword(encodePsw(IdUtil.simpleUUID()));
        user.setName(xm);

        // 保存用户
        saveOrUpdate(user);

        // 添加学生角色
        List<Integer> roles = new ArrayList<>();
        roles.add(3);
        addUserRoles(user.getUserId(), roles, true);

        return user;
    }

    @Override
    public List<IdNameVO> listCooperative() {
        return baseMapper.listCooperative();
    }

    @Async
    @Override
    public void saveLoginCount(String username) {
        List<User> userList = baseMapper.selectList(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, username)
        );
        if (userList.size() == 0) {
            return;
        }

        User user = userList.get(0);
        Integer loginCount = user.getLoginCount() != null ? user.getLoginCount() + 1 : 1;
        user.setLoginCount(loginCount);

        if (loginCount >= 3) {
            user.setState(Constants.DELETED_FALSE);
        }

        baseMapper.updateById(user);
    }
}
